// 逻辑越来越复杂，考虑状态机
#include "scr_oset.h"
#include "seg_msgbox.h"
#include "styles.h"
#include "app.h"
#include "tss_writer.h"
#include "components\polsys_lib\polsys_lib.h"
#include "components\battery_manager\battery_manager.h"
///////////////////// VARIABLES ////////////////////

extern lv_indev_t * MyIndev;

static void TimerHdl(lv_timer_t * timer);
static void ValueToDisplay();
static void SyncSliderToLable(uint8_t i);
static void UpdataStatusDisp();

// 屏幕（页面）句柄
lv_obj_t * Scr_OSet;

// 静态定义屏幕内的控件句柄。

static lv_obj_t * mStatusBar;
static lv_obj_t * mLableTime;
static lv_obj_t * mLablePortStatus;
static lv_obj_t * mLableStatus;        // 多页面时状态栏考虑独立起来

static lv_obj_t * mAppBar;      // 导航栏
static lv_obj_t * mLableRB;
static lv_obj_t * mLableLB;         // 多页面时导航栏考虑独立起来
static lv_obj_t * mTips;

static lv_obj_t * mSlider[10];
static lv_obj_t * mLableValue[10];

static lv_timer_t * mTimer;     // LVGL的软定时器

static lv_group_t * op_group;

static uint16_t mValues[10];    // 设置的10个输出值，单位mW

static u8 mKeyPressTime = 0;      // 按键按下计时

static u8 mDelayWriteTime = 0;      // 延时启动写入计时，延时的目的是等待界面显示完毕
static u8 mDelayReadTime = 0;       // 延时启动读取计时

///////////////////// TEST LVGL SETTINGS ////////////////////
//#if LV_COLOR_DEPTH != 16
//    #error "LV_COLOR_DEPTH should be 16bit to match SquareLine Studio's settings"
//#endif
//#if LV_COLOR_16_SWAP !=1
//    #error "LV_COLOR_16_SWAP should be 1 to match SquareLine Studio's settings"
//#endif

///////////////////// ANIMATIONS ////////////////////

// 键盘任意操作事件(键盘驱动发来的)
static void KeyBoard_Event(const keyboard_t * Sender)
{
    App_ClrIdleTime();

    if(Sender->LastStatus == KEY_STATUS_PRESS)  // 有键按下
    {
        mKeyPressTime = 0;    // 按键按下计时
        switch(Sender->LastKey)
        {
        case KEY_ESC:
        {
            uint8_t i;
            uint8_t value = lv_slider_get_value(mSlider[0]);
            for(i=1;i<10;i++)
            {
                lv_slider_set_value(mSlider[i], value, LV_ANIM_OFF);
                SyncSliderToLable(i);
            }
            App_SetDelayOff(5000);
            break;
        }
        // case KEY_OK:
        //     break;
        default: break;
        }
    }
    else    // 有键松手
    {
        switch(Sender->LastKey)
        {
        case KEY_ESC:
            if(BM_GetVolume() > 2)App_SetDelayOff(0);
            if(mKeyPressTime >= 10)MsgBox_Close();
            break;
        case KEY_OK:
            if(mKeyPressTime >= 10 && mKeyPressTime < 30)MsgBox_Close();
            break;
        default: break;
        }
    }
}

// 电池事件（电池管理组件发来的）
static void BMEvent(bm_event_t e)   // 此事件跟随状态栏
{
    UpdataStatusDisp();
    if(BM_GetDCConnectStatus() == false)
    {
        if(BM_GetVolume() <= 4)
        {
            MsgBox_Show("Low Battery!");
        }
        if(BM_GetVolume() <= 2)
        {
            MsgBox_Show("Low Battery!\rPower OFF.");
            App_SetDelayOff(2000);     // 2秒后关机
        }
    }
    if(e == BMEV_DC_PULL_IN)
    {
        MsgBox_TimerShow("Charging...", 2);
    }
}

// TSS读写器事件
static void TssWriterEvents(tw_ev_t e)
{
    switch(e)
    {
    case TW_EV_WR_OK:    // 写入成功
        lv_indev_set_group(MyIndev, op_group);  // 将键盘重新绑定到控件组（控件可操控）
        MsgBox_TimerShow("Succeed.", 2);  // 仅显示2秒
        break;
    case TW_EV_WR_FAIL:    // 写入失败
        lv_indev_set_group(MyIndev, op_group);  // 将键盘重新绑定到控件组（控件可操控）
        MsgBox_TimerShow("Fail.", 2);  // 仅显示2秒
        break;
    case TW_EV_RD_OK:
        lv_indev_set_group(MyIndev, op_group);  // 将键盘重新绑定到控件组（控件可操控）
        MsgBox_TimerShow("Completed.", 2);  // 仅显示2秒
        ValueToDisplay();
        break;
    case TW_EV_RD_FAIL:
        lv_indev_set_group(MyIndev, op_group);  // 将键盘重新绑定到控件组（控件可操控）
        MsgBox_TimerShow("Reading Fail.", 2);  // 仅显示2秒
        break;
    case TW_EV_RD_NONE:
        lv_indev_set_group(MyIndev, op_group);  // 将键盘重新绑定到控件组（控件可操控）
        MsgBox_TimerShow("Unsupported\rmode.You Need\rWrite First.", 4);  // 仅显示2秒
        break;
    case TW_EV_PLUG_IN:
        lv_label_set_text(mLablePortStatus, "Identify...");
        break;
    // case TW_EV_IDENTIFIED: // 已识别接入的设备（正品）
    //     lv_label_set_text(mLablePortStatus, "Authentic");
    //     lv_obj_add_style(mLablePortStatus, &Style_Genuine, LV_PART_MAIN | LV_STATE_DEFAULT);
    //     break;
    case TW_EV_UNKNOW_DEV:   // 接入了无法识别的设备（仿品）
        lv_label_set_text(mLablePortStatus, "Counterfeit");
        lv_obj_add_style(mLablePortStatus, &Style_Fake, LV_PART_MAIN | LV_STATE_DEFAULT);
        break;
    case TW_EV_INFO_UPDATE:
        lv_label_set_text(mLablePortStatus, "Authentic");
        lv_obj_add_style(mLablePortStatus, &Style_Genuine, LV_PART_MAIN | LV_STATE_DEFAULT);
        UpdataStatusDisp();
        break;
    case TW_EV_PLUG_OUT:
        lv_label_set_text(mLablePortStatus, "NC/Counterfeit");
        lv_obj_remove_style(mLablePortStatus, &Style_Fake, LV_PART_MAIN | LV_STATE_ANY);
        lv_obj_remove_style(mLablePortStatus, &Style_Genuine, LV_PART_MAIN | LV_STATE_ANY);
        UpdataStatusDisp();
        break;
    default: break;
    }
}

void BleGapEvent(ble_gap_st_t new_st)
{
    UpdataStatusDisp();
}


// 页面已加载事件
static void ScrEventLoaded(lv_event_t * e)
{
    // lv_event_code_t event_code = lv_event_get_code(e);// 获取当前事件代码
    // lv_obj_t * target = lv_event_get_target(e); // 获取发送事件的对象
    // LOG("SlidersEvents:%d from %X\r\n",event_code,target);
    TW_SetCb(TssWriterEvents);
    BM_SetCb(BMEvent);
    Keyboard_SetEventCb(KeyBoard_Event);
    Ble_SetGapEventCb(BleGapEvent);
    UpdataStatusDisp();

    // ValueToDisplay();

    // 创建软定时器
    mTimer = lv_timer_create(TimerHdl, 100,  NULL);
}

// 页面已取消加载事件（在加载下一个页面前）
static void ScrEventUnLoaded(lv_event_t * e)
{
    // 删除软定时器
    lv_timer_del(mTimer);
}

// 100ms 软定时器
static void TimerHdl(lv_timer_t * timer)
{
    // 长按处理
    if(Keyboard_GetLastStatus() == KEY_STATUS_PRESS)
    {
        mKeyPressTime++;
        if(mKeyPressTime % 10 == 0)  // 1s长按，按住后每隔1s执行一次
        {
            switch(Keyboard_GetLastKey())
            {
            case KEY_ESC:
            {
                char text_buff[30];
                lv_snprintf(text_buff, sizeof(text_buff), "Turn off after %ds.", 5 - mKeyPressTime/10);
                MsgBox_Show(text_buff);
                break;
            }
            case KEY_OK:
            {
                if(mKeyPressTime < 30)
                {
                    char text_buff[30];
                    lv_snprintf(text_buff, sizeof(text_buff), "Start to read after\r %ds.", 3 - mKeyPressTime/10);
                    MsgBox_Show(text_buff);
                }
                else if(mKeyPressTime == 30)
                // if(mKeyPressTime == 10) // 长按1秒执行一次
                {
                    tw_status_t st = TW_GetStatus();
                    if(st == TW_ST_GENUINE || st == TW_ST_GENUINE_TO)
                    {
                        lv_indev_set_group(MyIndev, NULL);      // 将输入设备绑定到消息框中的可操作控件组（模态，目前没有可操作控件，设置为NULL）
                        MsgBox_Show("Reading...");   //注意：只是创建，显示是异步的，刷屏结束前数据可能已经发完了，会耽误接收从机返回数据。 解决方案：确保显示已刷新后启动写入。
                        mDelayReadTime = 3;    // 300ms之后读取
                    }
                    else
                    {
                        MsgBox_TimerShow("No connection.", 2);  // 仅显示2秒
                    }
                    
                }
                break;
            }
            default: break;
            }
        }
    }

    // 延时启动写入
    if(mDelayWriteTime == 1)
    {
        if(!TW_StartWrite(mValues))     // 开始写入，写入完毕后触发回调
        {
            lv_indev_set_group(MyIndev, op_group);  // 将键盘重新绑定到控件组（控件可操控）
            MsgBox_TimerShow("This Model\rnot supported.", 3);  // 仅显示3秒
        }
        mDelayWriteTime = 0;
    }
    if(mDelayWriteTime > 0)mDelayWriteTime--;

    // 延时启动读取
    if(mDelayReadTime == 1)
    {
        if(!TW_StartRead(mValues))     // 开始读取，读取完毕后触发回调，数据存放在 mValues 中。
        {
            lv_indev_set_group(MyIndev, op_group);  // 将键盘重新绑定到控件组（控件可操控）
            MsgBox_TimerShow("This Model\rnot supported.", 3);  // 仅显示3秒
        }
        mDelayReadTime = 0;
    }
    if(mDelayReadTime > 0)mDelayReadTime--;

}

// 所有的 Slider 控件事件
static void SlidersEvents(lv_event_t * e)
{
    lv_event_code_t event_code = lv_event_get_code(e);// 获取当前事件代码
    // lv_obj_t * target = lv_event_get_target(e); // 获取发送事件的对象
    // LOG("SlidersEvents:%d from %X\r\n",event_code,target);
    if(event_code == LV_EVENT_VALUE_CHANGED) 
    {
        SyncSliderToLable((int)lv_event_get_user_data(e));
    }
    else if(event_code == LV_EVENT_SHORT_CLICKED)   // 单击了控件
    {
        tw_status_t st = TW_GetStatus();
        if(st == TW_ST_GENUINE || st == TW_ST_GENUINE_TO)
        {
            uint8_t i;

            lv_indev_set_group(MyIndev, NULL);      // 将输入设备绑定到消息框中的可操作控件组（模态，目前没有可操作控件，设置为NULL）
            MsgBox_Show("Writing...");   //注意：只是创建，显示是异步的，刷屏结束前数据可能已经发完了，会耽误接收从机返回数据。 解决方案：确保显示已刷新后启动写入。
            for(i=0;i<10;i++)
            {
                // mValues[i] = IntSqrt(lv_slider_get_value(mSlider[i]) * (u32)((float)500000 * 0.8)); // 转换成有效电压
                mValues[i] = lv_slider_get_value(mSlider[i]) * 500; // mW
            }
            mDelayWriteTime = 3;    // 300ms之后写入
        }
        else
        {
            MsgBox_TimerShow("No connection.", 2);  // 仅显示2秒
        }
    }
}

///////////////////// FUNCTIONS ////////////////////

static void ValueToDisplay()
{
    uint8_t i;
    for(i = 0; i<10;i++)
    {
        lv_slider_set_value(mSlider[i], mValues[i]/500, LV_ANIM_OFF);
        SyncSliderToLable(i);
    }
}

// 同步 Slider 的值到 Lable
// i - 第几个Slider
static void SyncSliderToLable(uint8_t i)
{
    char text_buff[8];
    uint8_t value = lv_slider_get_value(mSlider[i]);
    lv_snprintf(text_buff, sizeof(text_buff), "%d.%d", value/2,value%2*5);
    lv_label_set_text(mLableValue[i], text_buff);
}

static void UpdataStatusDisp()
{
    char text_buff[20];
    if(BM_GetDCConnectStatus())
    {
        if(BM_GetChargeStatus())
        {
            lv_snprintf(text_buff, sizeof(text_buff), "CHG.%d%%", BM_GetVolume());
        }
        else
        {
            lv_snprintf(text_buff, sizeof(text_buff), "F.%d%%", BM_GetVolume());
        }
    }
    else
    {
        lv_snprintf(text_buff, sizeof(text_buff), "%d%%", BM_GetVolume());;
    }
    lv_label_set_text(mLableStatus, text_buff);

    tw_status_t st = TW_GetStatus();
    if(st == TW_ST_GENUINE || st == TW_ST_GENUINE_TO)
    {
        u8 batt_level = TW_GetDevInfo()->BattLevel;
        if(batt_level <= 100)   // 大于100表示无法获取电量
        {
            lv_snprintf(text_buff, sizeof(text_buff), "%d%%.", batt_level);
            lv_label_ins_text(mLableStatus, 0, text_buff);
        }
    }

    ble_gap_st_t bst = Ble_GetGapState();
    if(bst == BLE_GAP_ST_CONNECTED)
    {
        lv_label_ins_text(mLableStatus, 0, "BLE.");
    }
}

///////////////////// SCREEN /////////////////////
void Scr_OSetInit(void)
{
    uint8_t i;

    // 创建并设置组，组用于键盘操作。
    op_group = lv_group_create(); 
    lv_group_set_default(op_group);
    lv_indev_set_group(MyIndev, op_group);

    // 创建并设置屏幕，不用设置尺寸？
    Scr_OSet = lv_obj_create(NULL);
    lv_obj_add_style(Scr_OSet, &Style_ScrDefault, LV_PART_MAIN | LV_STATE_DEFAULT);
    lv_obj_add_event_cb(Scr_OSet, ScrEventLoaded, LV_EVENT_SCREEN_LOADED, NULL);
    lv_obj_add_event_cb(Scr_OSet, ScrEventUnLoaded, LV_EVENT_SCREEN_UNLOADED, NULL);

// 多页面时状态栏考虑独立起来

    mStatusBar = lv_obj_create(Scr_OSet);
    lv_obj_set_width(mStatusBar, 320);
    lv_obj_set_height(mStatusBar, 16);
    lv_obj_set_align(mStatusBar, LV_ALIGN_TOP_MID);
    lv_obj_add_style(mStatusBar, &Style_StatusBar, LV_PART_MAIN | LV_STATE_DEFAULT);

    mLableTime = lv_label_create(mStatusBar);
    lv_obj_set_width(mLableTime, LV_SIZE_CONTENT);   /// 1
    lv_obj_set_height(mLableTime, LV_SIZE_CONTENT);    /// 1
    lv_obj_set_align(mLableTime, LV_ALIGN_LEFT_MID);
    lv_label_set_text(mLableTime, "TSS Reader");

    mLablePortStatus = lv_label_create(mStatusBar);
    lv_obj_set_width(mLablePortStatus, LV_SIZE_CONTENT);   /// 1
    lv_obj_set_height(mLablePortStatus, LV_SIZE_CONTENT);    /// 1
    lv_obj_set_align(mLablePortStatus, LV_ALIGN_CENTER);
    lv_label_set_text(mLablePortStatus, "NC/Counterfeit");

    mLableStatus = lv_label_create(mStatusBar);
    lv_obj_set_width(mLableStatus, LV_SIZE_CONTENT);   /// 1
    lv_obj_set_height(mLableStatus, LV_SIZE_CONTENT);    /// 1
    lv_obj_set_align(mLableStatus, LV_ALIGN_RIGHT_MID);
    lv_label_set_text(mLableStatus, "E");

// 多页面时导航栏考虑独立起来
    mAppBar = lv_obj_create(Scr_OSet);
    lv_obj_set_width(mAppBar, 320);
    lv_obj_set_height(mAppBar, 16);
    lv_obj_set_align(mAppBar, LV_ALIGN_BOTTOM_MID);
    lv_obj_add_style(mAppBar, &Style_StatusBar, LV_PART_MAIN | LV_STATE_DEFAULT);

    mLableRB = lv_label_create(mAppBar);
    lv_obj_set_width(mLableRB, LV_SIZE_CONTENT);   /// 1
    lv_obj_set_height(mLableRB, LV_SIZE_CONTENT);    /// 1
    lv_obj_set_align(mLableRB, LV_ALIGN_RIGHT_MID);
    lv_label_set_text_static(mLableRB, "OK");

    mLableLB = lv_label_create(mAppBar);
    lv_obj_set_width(mLableLB, LV_SIZE_CONTENT);   /// 1
    lv_obj_set_height(mLableLB, LV_SIZE_CONTENT);    /// 1
    lv_obj_set_align(mLableLB, LV_ALIGN_LEFT_MID);
    lv_label_set_text_static(mLableLB, "Left Align/OFF");

    mTips = lv_label_create(mAppBar);
    lv_obj_set_width(mTips, LV_SIZE_CONTENT);   /// 1
    lv_obj_set_height(mTips, LV_SIZE_CONTENT);    /// 1
    lv_obj_set_align(mTips, LV_ALIGN_CENTER);
    lv_label_set_text(mTips, "Unit W.");

    for(i = 0; i < 10; i++)
    {
        mSlider[i] = lv_slider_create(Scr_OSet);
        lv_slider_set_range(mSlider[i], 0, 30);
        lv_slider_set_value(mSlider[i], 24, LV_ANIM_OFF);
        lv_obj_set_width(mSlider[i], 3);
        lv_obj_set_height(mSlider[i], 180);
        lv_obj_set_x(mSlider[i], 20 + i * 31);
        lv_obj_set_y(mSlider[i], -5);
        lv_obj_set_align(mSlider[i], LV_ALIGN_LEFT_MID);
        lv_obj_add_style(mSlider[i], &Style_SliderMain, LV_PART_MAIN | LV_STATE_DEFAULT);
        lv_obj_add_style(mSlider[i], &Style_SliderIndicator, LV_PART_INDICATOR | LV_STATE_DEFAULT);
        lv_obj_add_style(mSlider[i], &Style_SliderKnob, LV_PART_KNOB | LV_STATE_DEFAULT);
        lv_obj_add_style(mSlider[i], &Style_SliderKnobFoc, LV_PART_KNOB | LV_STATE_FOCUSED);

        mLableValue[i] = lv_label_create(Scr_OSet);
        lv_obj_set_width(mLableValue[i], LV_SIZE_CONTENT);   /// 1
        lv_obj_set_height(mLableValue[i], LV_SIZE_CONTENT);    /// 1
        lv_obj_set_x(mLableValue[i], 11 + i * 31);
        lv_obj_set_y(mLableValue[i], 95);
        lv_obj_set_align(mLableValue[i], LV_ALIGN_LEFT_MID);
        lv_label_set_text(mLableValue[i], "12.0");

        lv_obj_add_event_cb(mSlider[i], SlidersEvents, LV_EVENT_VALUE_CHANGED, (void *)i);
        lv_obj_add_event_cb(mSlider[i], SlidersEvents, LV_EVENT_SHORT_CLICKED, (void *)i);
    }
}
